/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*          http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <string.h>

// this should be enough
static char buf[65536] = {};
static char code_buf[65536 + 128] = {}; // a little larger than `buf`
static char *code_format =
"#include <stdio.h>\n"
"int main() { "
"  unsigned result = %s; "
"  printf(\"%%u\", result); "
"  return 0; "
"}";

static void gen_rand_op() ;
static int pos = 0;
static int last_is_num = 0;
static void gen_num() {
  int n = rand()%100;
  if(n < 0) n = -n;
  pos += sprintf(buf+pos,"%d",n);
}

static void gen(char c) {
  buf[pos] = c;
  pos++;
}

static void gen_rand_op() {
  char *op_table[] = {"+","-","*","/","==","!=","&&"};
  int n = rand()%3;
  if(n < 0) n = -n;
  buf[pos++] = op_table[n][0];
  if(n > 3) {
    buf[pos++] = op_table[n][1];
  }
  last_is_num = 0;
}
int choose(int n) {
  int num = rand()%n;
  if(num < 0) num = -num;
  return num;
}
static void gen_rand_expr() {
  if(last_is_num)  gen_rand_op();
  switch (choose(3)) {
    case 0: gen_num(); last_is_num = 1; break;
    case 1: gen('('); last_is_num = 0; gen_rand_expr(); gen(')'); last_is_num = 1; break;
    default: gen_rand_expr(); gen_rand_op(); gen_rand_expr(); last_is_num = 1; break;
  }
}

int main(int argc, char *argv[]) {
  int seed = time(0);
  srand(seed);
  int loop = 1;
  if (argc > 1) {
    sscanf(argv[1], "%d", &loop);
  }
  int i;
  for (i = 0; i < loop; i ++) {
    last_is_num = 0;
    pos = 0;
    gen_rand_expr();
    buf[pos] = 0;
    sprintf(code_buf, code_format, buf);

    FILE *fp = fopen("/tmp/.code.c", "w");
    assert(fp != NULL);
    fputs(code_buf, fp);
    fclose(fp);

    int ret = system("gcc /tmp/.code.c -o /tmp/.expr");
    if (ret != 0) continue;

    fp = popen("/tmp/.expr", "r");
    assert(fp != NULL);

    int result;
    int temp_val = fscanf(fp, "%d", &result);
    while(0) {
      if(temp_val != 0)
      temp_val = 0;
    }
    pclose(fp);

    printf("%u %s\n", result, buf);
  }
  return 0;
}
